package org.gfix.binding;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.math.BigDecimal;

import org.gfix.binding.ClassFixBindingDescription;
import org.gfix.binding.FixBindingContext;
import org.gfix.binding.FixBindingMetaData;
import org.gfix.types.FixVersion;
import org.junit.Test;

public class Basic_FIXTOObject_ClassFixBindingDescriptionTest
{

	@Test
	public void testClassFixBindingDescription() throws Exception 
	{
		ClassFixBindingDescription desc = new ClassFixBindingDescription(SimpleBoundType.class);
		FixBindingMetaData fbmd = desc.getMetadata(FixVersion.FIX_40);
		assertNotNull(fbmd);
		assertEquals(12, fbmd.getMappedFields());
		
		// now check we can push values into the object.
		SimpleBoundType type = new SimpleBoundType();
		FixBindingContext context = new FixBindingContext();
		context.setBoundObject(type);
		
		fbmd.setValue(61, "true", context);
		assertTrue(type.isBooleanType());
		fbmd.setValue(62, "C", context);
		assertEquals('C',type.getCharacterType());
		
		fbmd.setValue(63, "67", context);
		assertEquals(67,type.getByteType());
		
		fbmd.setValue(64, "12", context);
		assertEquals(12,type.getShortType());
		
		fbmd.setValue(65, "34567", context);
		assertEquals(34567,type.getIntegerType());
		
		fbmd.setValue(66, "34567346546743", context);
		assertEquals(34567346546743L,type.getLongType());
		
		fbmd.setValue(67, "12345.6789", context);
		assertEquals(12345.6789f,type.getFloatType(),0.0);
		
		fbmd.setValue(68, "12345.6789", context);
		assertEquals(12345.6789,type.getDoubleType(),0.0);
		
		fbmd.setValue(69, "hello fix bindings this is great", context);
		assertEquals("hello fix bindings this is great",type.getStringType());
		
		fbmd.setValue(70, "1.23356", context);
		assertEquals(new BigDecimal("1.23356"),type.getBigDecimalType());
		
		fbmd.setValue(71, "FIX.4.0", context);
		assertEquals(FixVersion.FIX_40,type.getVersion());
		
		fbmd.setValue(72, "HELLO", context);
		assertEquals(SimpleEnumType.HELLO,type.getSimpleEnumType());
	}
	
	
	@Test
	public void testClassFix41BindingDescription() throws Exception 
	{
		ClassFixBindingDescription desc = new ClassFixBindingDescription(SimpleBoundType.class);
		FixBindingMetaData fbmd = desc.getMetadata(FixVersion.FIX_41);
		assertNotNull(fbmd);
		assertEquals(12, fbmd.getMappedFields());
		
		// now check we can push values into the object.
		SimpleBoundType type = new SimpleBoundType();
		FixBindingContext context = new FixBindingContext();
		context.setBoundObject(type);
		fbmd.setValue(71, "true", context);
		assertTrue(type.isBooleanType());
		fbmd.setValue(70, "C", context);
		assertEquals('C',type.getCharacterType());
		
		fbmd.setValue(69, "67", context);
		assertEquals(67,type.getByteType());
		
		fbmd.setValue(68, "12", context);
		assertEquals(12,type.getShortType());
		
		fbmd.setValue(67, "34567", context);
		assertEquals(34567,type.getIntegerType());
		
		fbmd.setValue(66, "34567346546743", context);
		assertEquals(34567346546743L,type.getLongType());
		
		fbmd.setValue(65, "12345.6789", context);
		assertEquals(12345.6789f,type.getFloatType(),0.0);
		
		fbmd.setValue(64, "12345.6789", context);
		assertEquals(12345.6789,type.getDoubleType(),0.0);
		
		fbmd.setValue(63, "hello fix bindings this is great", context);
		assertEquals("hello fix bindings this is great",type.getStringType());
		
		fbmd.setValue(62, "1.23356", context);
		assertEquals(new BigDecimal("1.23356"),type.getBigDecimalType());
		
		fbmd.setValue(61, "FIX.4.0", context);
		assertEquals(FixVersion.FIX_40,type.getVersion());
		
		fbmd.setValue(60, "WORLD", context);
		assertEquals(SimpleEnumType.WORLD,type.getSimpleEnumType());
	}

	@Test
	public void testSimpleConverter() throws Exception
	{
		ClassFixBindingDescription desc = new ClassFixBindingDescription(
				SimpleConverterType.class);
		FixBindingMetaData fbmd = desc.getMetadata(FixVersion.FIX_40);
		assertNotNull(fbmd);
		SimpleConverterType output = new SimpleConverterType();
		FixBindingContext context = new FixBindingContext();
		context.setBoundObject(output);
		fbmd.setValue(72, "lowerName", context);
		assertEquals("LOWERNAME",output.getName());
	}
	
	@Test
	public void testSimpleNested() throws Exception
	{
		ClassFixBindingDescription desc = new ClassFixBindingDescription(
				SimpleNestedBoundType.class);
		FixBindingMetaData fbmd = desc.getMetadata(FixVersion.FIX_40);
		assertNotNull(fbmd);
		SimpleNestedBoundType output = new SimpleNestedBoundType();
		FixBindingContext context = new FixBindingContext();
		context.setBoundObject(output);
		fbmd.setValue(70, "lowerName", context);
		fbmd.setValue(72, "LOWERNAMETWO", context);

		assertEquals("lowerName",output.getName());
		assertEquals("LOWERNAMETWO",output.getSubObject().getName());
		
	}
	
	@Test
	public void testSimpleGroupBinding() throws Exception
	{
		ClassFixBindingDescription desc = new ClassFixBindingDescription(
				SimpleRepeatingGroupParentType.class);
		FixBindingMetaData fbmd = desc.getMetadata(FixVersion.FIX_44);
		assertNotNull(fbmd);
		SimpleRepeatingGroupParentType output = new SimpleRepeatingGroupParentType();
		FixBindingContext context = new FixBindingContext();
		context.setBoundObject(output);
		fbmd.setValue(69, "beforeGroup", context);
		// start the repeating group.
		fbmd.setValue(70, "2", context);
		//group 1
		fbmd.setValue(71, "3", context);
		fbmd.setValue(72, "Type0", context);
		// group 2
		fbmd.setValue(71, "2", context);
		fbmd.setValue(72, "Type1", context);
		
		// tag after group
		fbmd.setValue(68, "postGroup", context);
		
		assertEquals("beforeGroup",output.getGroupIdentifier());
		assertEquals("postGroup",output.getPostGroupIdentifier());
		assertNotNull(output.getGroup());
		assertEquals(2,output.getGroup().size());
		int i = 0;
		for(SimpleRepeatingGroupType rG : output.getGroup())
		{
			assertEquals(3-i, rG.getIndex());
			assertEquals("Type"+i, rG.getType());
			i++;
		}
	}
	
	@Test
	public void testNestedGroups() throws Exception
	{
		ClassFixBindingDescription desc = new ClassFixBindingDescription(
				NestedGroupsType.class);
		int items = 5;
		
		FixBindingMetaData fbmd = desc.getMetadata(FixVersion.FIX_44);
		assertNotNull(fbmd);
		NestedGroupsType output = new NestedGroupsType();
		FixBindingContext context = new FixBindingContext();
		context.setBoundObject(output);
		
		fbmd.setValue(100, "beforeGroup", context);
		fbmd.setValue(101, String.valueOf(items), context);
		for(int i = 0 ; i < items; i ++)
		{
		
			fbmd.setValue(69, "beforeGroup"+i, context);
			fbmd.setValue(500, "Unmapped", context);
			// start the repeating group.
			fbmd.setValue(70, "2", context);
			//group 1
			fbmd.setValue(71, "3", context);
			fbmd.setValue(777, "Unmapped", context);
			fbmd.setValue(72, "Type0"+i, context);
			// group 2
			fbmd.setValue(71, "2", context);
			fbmd.setValue(777, "Unmapped", context);
			fbmd.setValue(72, "Type1"+i, context);
			
			// tag after group
			fbmd.setValue(501, "Unmapped", context);
			fbmd.setValue(68, "postGroup"+i, context);
		}
		fbmd.setValue(102, "postGroup", context);
		
		// now have to inspect the built up object.
		
		assertEquals("beforeGroup",output.getNestedGroupsTypeBefore());
		assertEquals("postGroup",output.getNestedGroupsAfter());
		assertNotNull(output.getItems());
		assertEquals(5,output.getItems().size());
		int j = 0;
		for(SimpleRepeatingGroupParentType parent : output.getItems())
		{			
			assertEquals("beforeGroup"+j,parent.getGroupIdentifier());
			assertEquals("postGroup"+j,parent.getPostGroupIdentifier());
			assertNotNull(parent.getGroup());
			assertEquals(2,parent.getGroup().size());
			int i = 0;
			for(SimpleRepeatingGroupType rG : parent.getGroup())
			{
				assertEquals(3-i, rG.getIndex());
				assertEquals("Type"+i+""+j, rG.getType());
				i++;
			}
			j++;
		}
	}
	
	
	@Test
	public void testSimpleGroupWithUnmappedTaginGroupBinding() throws Exception
	{
		ClassFixBindingDescription desc = new ClassFixBindingDescription(
				SimpleRepeatingGroupParentType.class);
		FixBindingMetaData fbmd = desc.getMetadata(FixVersion.FIX_44);
		assertNotNull(fbmd);
		SimpleRepeatingGroupParentType output = new SimpleRepeatingGroupParentType();
		FixBindingContext context = new FixBindingContext();
		context.setBoundObject(output);
		fbmd.setValue(69, "beforeGroup", context);
		// start the repeating group.
		fbmd.setValue(70, "2", context);
		//group 1
		fbmd.setValue(71, "3", context);
		fbmd.setValue(77, "Unmapped", context);
		fbmd.setValue(72, "Type0", context);
		// group 2
		fbmd.setValue(71, "2", context);
		fbmd.setValue(77, "Unmapped", context);
		fbmd.setValue(72, "Type1", context);
		
		// tag after group
		fbmd.setValue(68, "postGroup", context);
		
		assertEquals("beforeGroup",output.getGroupIdentifier());
		assertEquals("postGroup",output.getPostGroupIdentifier());
		assertNotNull(output.getGroup());
		assertEquals(2,output.getGroup().size());
		int i = 0;
		for(SimpleRepeatingGroupType rG : output.getGroup())
		{
			assertEquals(3-i, rG.getIndex());
			assertEquals("Type"+i, rG.getType());
			i++;
		}
	}
}
